home *** CD-ROM | disk | FTP | other *** search
- #include "config.h"
-
- #include <Types.h>
- #include <ctype.h>
- #include <string.h>
- #include <strings.h>
- #include <stdio.h>
- #include <Events.h>
- #include <Sound.h>
- #include <Resources.h>
-
- char *copy_string();
-
- #define MAXRULES 100
-
- #define MAXARGS 5
-
- struct rule {
- char *key;
- char *args[MAXARGS];
- char *soundname;
- };
-
- struct rule *rules;
-
- int talking = 0;
-
- int rude = 0;
-
- int numrules = 0;
-
- char *commentarypath = NULL;
-
- /* Implementation of talking compiler features. */
-
- init_talk (char *str, char *prog)
- {
- int i;
- char *substr = NULL, line[300], *charpos;
- Str255 tmpstr;
- FILE *fp;
-
- talking = 1;
- if (strcmp(str, "talk-rudely") == 0) {
- rude = 1;
- }
- /* Seed the RNG so that we get random choices. */
- srand(TickCount());
- /* Allocate working space. */
- commentarypath = (char *) xmalloc(255);
- rules = (struct rule *) xmalloc(MAXRULES * sizeof(struct rule));
- if (getenv("COMMENTARY")) {
- sprintf(commentarypath, "%s", getenv("COMMENTARY"));
- } else if (getenv("MPW")) {
- sprintf(commentarypath, "%sCommentary:", getenv("MPW"));
- } else {
- sprintf(commentarypath, ":");
- }
- sprintf (tmpstr, " %sSounds", commentarypath);
- tmpstr[0] = strlen (str);
- OpenResFile (tmpstr);
- /* For testing */
- if (str[4] == 'T') {
- substr = str+5;
- talk (substr, "testing");
- }
- /* Try to read a rule file that adds to or replaces the builtin rules. */
- sprintf (tmpstr, "%sRules", commentarypath);
- if ((fp = fopen (tmpstr, "r")) != NULL) {
- while (fgets(line, 300 - 1, fp) != NULL) {
- line[strlen(line)-1] = '\0'; /* should blast all trailing whitespace too */
- /* Interpret '//' as a comment, blast everything following on line. */
- if ((charpos = strchr(line, '/')) != NULL && *(charpos+1) == '/')
- *charpos = '\0';
- /* Very crude parsing. */
- if ((charpos = strrchr(line, ':')) != NULL) {
- *charpos = '\0';
- /* (should filter leading/trailing whitespace) */
- rules[numrules].soundname = copy_string(charpos+1);
- for (i = 0; i < MAXARGS; ++i) {
- rules[numrules].args[i] = NULL;
- }
- /* Parse the rule into keyword and argument. */
- if ((charpos = strchr(line, ' ')) != NULL) {
- *charpos = '\0';
- rules[numrules].key = copy_string(line);
- rules[numrules].args[0] = copy_string(charpos+1);
- } else {
- rules[numrules].key = copy_string(line);
- }
- ++numrules;
- if (numrules >= MAXRULES) break;
- }
- }
- fclose (fp);
- }
- /* Just to kick things off. */
- comment ("start", prog);
- }
-
- /* Try to match the given situation and issue a comment on it. */
-
- comment(char *str, char *arg1, char *arg2, char *arg3)
- {
- int i, j = 0, matched, numchoices, choices[20];
- int jg = 0, matchedgeneric, numgenericchoices, genericchoices[20];
- int commented = 0;
- char *rulearg, buf[255];
-
- if (talking == 0) return;
- if (str == NULL) return;
- for (i = 0; i < numrules; ++i) {
- if (strcmp(str, rules[i].key) == 0) {
- matched = matchedgeneric = 0;
- rulearg = rules[i].args[0];
- if (strcmp(str, "start") == 0
- || strcmp(str, "finish") == 0) {
- /* Require an exact match if arg supplied. */
- if (arg1 != NULL && rulearg != NULL) {
- if (strcmp(arg1, rulearg) == 0) matched = 1;
- } else if (rulearg == NULL) {
- matchedgeneric = 1;
- }
- } else if (strcmp(str, "include") == 0
- || strcmp(str, "macro") == 0
- || strcmp(str, "function") == 0
- || strcmp(str, "call") == 0
- || strcmp(str, "error") == 0
- || strcmp(str, "warning") == 0) {
- /* Match on a substring. */
- if (arg1 != NULL && rulearg != NULL) {
- if (strstr(arg1, rulearg) != NULL) matched = 1;
- } else if (rulearg == NULL) {
- matchedgeneric = 1;
- }
- } else {
- /* Otherwise always match the rule, indep of any args. */
- matchedgeneric = 1;
- }
- if (matched && j < 20) choices[j++] = i;
- if (matchedgeneric && jg < 20) genericchoices[jg++] = i;
- }
- }
- numgenericchoices = jg;
- numchoices = j;
- sprintf(buf, "--- Saw %s, arg \"%s\" ---\n",
- (str ? str : "???"),
- (arg1 ? arg1 : "???"));
- if (numchoices > 0) {
- for (i = 0; i < numchoices; ++i) {
- j = (rand() >> 8) % numchoices;
- if (talk (rules[choices[j]].soundname, buf)) {
- break;
- }
- }
- } else if (numgenericchoices > 0) {
- for (i = 0; i < numgenericchoices; ++i) {
- j = (rand() >> 8) % numgenericchoices;
- if (talk (rules[genericchoices[j]].soundname, buf)) {
- break;
- }
- }
- }
- }
-
- /* Given a string naming a sound, try to find and play it. Return true if
- successfully played, false otherwise. */
-
- talk (char *str, char *buf)
- {
- short refnum = 0, num, i;
- int openedfile = 0, played = 0;
- Handle soundhandle = nil, tmphandle;
- Str255 tmpstr;
-
- if (!talking) return 0;
- if (str == NULL) return 0;
- /* If the string is empty, pretend we succeeded, but without saying anything.
- This is how a rule can disable commentary coming from more general rules. */
- if (strlen(str) == 0) return 1;
- /* First try loading a sound with a matching name that is already visible
- in the resource chain. */
- sprintf (tmpstr, " %s", str);
- tmpstr[0] = strlen (str);
- soundhandle = GetNamedResource ('snd ', tmpstr);
- if (soundhandle == nil) {
- /* Now try looking for a sound file with a matching name, open it,
- and play the first resource (since sound file resource seems to
- have random name/id) */
- sprintf(tmpstr, " %s%s", commentarypath, str);
- tmpstr[0] = strlen (tmpstr+1);
- if ((refnum = OpenResFile(tmpstr)) != -1) {
- openedfile = 1;
- /* Look for the first resource in the just-opened file. */
- num = CountResources('snd ');
- for (i = 1; i < num; ++i) {
- tmphandle = GetIndResource('snd ', i);
- if (HomeResFile(tmphandle) == refnum) {
- soundhandle = tmphandle;
- break;
- }
- }
- }
- }
- /* Play the sound if it exists. */
- if (soundhandle != nil) {
- /* should bring up a window with this in it */
- fprintf(stderr, "\n%s\n", buf);
- SndPlay (nil, soundhandle, 0);
- played = 1;
- }
- /* Close any resource files that were opened especially for this call. */
- if (openedfile) {
- CloseResFile(refnum);
- }
- if (!played) fprintf(stderr, "Warning: couldn't play \"%s\"\n", str);
- return played;
- }
-
- #if 0 /* def DO_SPEECH */
-
- /* Lifted from TTESample, not actually used */
-
- #include "Speech.h"
-
-
- #pragma segment Main
- OSErr SpeakTextRange(TEHandle te, short sIndex, short eIndex)
- {
- long i;
- long len;
- Ptr textPtr;
- OSErr err = noErr;
-
- if (!te) /* no TERecord to work with */
- return nilHandleErr;
-
- textPtr = *((*te)->hText); /* get ptr to TERecord text */
-
- len = eIndex - sIndex; /* total length of text to speak */
-
- if (len <= 0) /* nothing to speak */
- return noErr;
-
- if (len > 4095)
- len = 4095;
-
- for (i = 0; i < len; i++) /* copy over the chars we want to speak */
- gTextBuf[i] = textPtr[sIndex + i];
-
- gTextBufLen = (unsigned short) len;
-
- if (len > 255)
- len = 255; /* limit length to Str255 max for now */
-
- for (i = 1; i <= len; i++) /* copy over the chars we want to speak */
- gSpeechStr[i] = textPtr[sIndex + i - 1];
-
- gSpeechStr[0] = (unsigned char) len;
-
- if (!gSpeechChan)
- {
- if (voiceSel == 0)
- err = NewSpeechChannel(0, &gSpeechChan);
- else
- err = NewSpeechChannel(&vspec[voiceSel], &gSpeechChan);
-
- if (err != noErr)
- AlertUser(eSpeechManager); /* some kind of error */
- }
-
- if (err == noErr)
- {
- if (!SpeechBusy())
- {
- err = SpeakBuffer(gSpeechChan, (Ptr) gTextBuf, gTextBufLen, 0);
-
- if (err != noErr)
- AlertUser(eSpeechManager); /* some kind of error */
- }
- else
- SysBeep(10);
- }
-
- return err;
- }
-
-
-
-
-
- #pragma segment Main
- void StartupSpeech( void )
- {
- OSErr err;
- short voiceCount;
- short i;
- VoiceDescription vd;
- MenuHandle voiceMenu;
- NumVersion ver = SpeechManagerVersion();
-
- #ifndef forRez
- enum {development=0x20, alpha=0x40, beta=0x60, final=0x80, release=0x80};
- #endif
-
- #define kMgrMajorVersion 1 /* 8-bits */
- #define kMgrMinorVersion 0 /* 4-bits */
- #define kMgrBugFixVersion 0 /* 4-bits */
- #define kMgrDevelopmentStage alpha /* 8-bits */
- #define kMgrNonRelVersion 2 /* 8-bits */
-
- #define kSpeechManagerVersion ((kMgrMajorVersion << 24) \
- | (kMgrMinorVersion << 20) \
- | (kMgrBugFixVersion << 16) \
- | (kMgrDevelopmentStage << 8) \
- | (kMgrNonRelVersion))
-
- voiceMenu = GetMHandle (mVoice);
-
- err = CountVoices(&voiceCount);
- if (voiceCount > kMaxVoices-1) voiceCount = kMaxVoices-1;
- for (i = 1; i <= voiceCount; i++)
- {
- err = GetIndVoice(i, &vspec[i]);
-
- if ( true || ((*( unsigned long *) (&ver)) >= kSpeechManagerVersion))
- { // newer versions expect you to pass length in parameter list
- err = GetVoiceDescription(&vspec[i], &vd, sizeof(VoiceDescription));
- }
- else
- {
- //vd.length = sizeof(VoiceDescription); // early versions require you to set length field
- //err = GetVoiceDescription(&vspec[i], &vd);
- }
- AppendMenu (voiceMenu, vd.name);
- }
- voiceSel = 0; // use Default voice
- }
-
- #endif /* DO_SPEECH */
-
-